package com.qdd.freight.handler.impl;

import com.qdd.freight.anno.Mode;
import com.qdd.freight.entity.Datas;
import com.qdd.freight.exception.FreightCountFailureException;
import com.qdd.freight.exception.FreightToBeZeroExcption;
import com.qdd.freight.exception.OutOfLimitException;
import com.qdd.freight.handler.AbstractLogisticsHandler;
import com.qdd.freight.mapper.LogisticsRegionMapper;
import com.qdd.freight.pojo.GoodsShip;
import com.qdd.freight.pojo.Logistics;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Map;

/**
 * 整车运输
 *
 * @ClassName NormalLogisticsHandler
 * @Description TODO
 * @Author yanpeihao
 * @Date 2019/12/6 22:47
 * @Version 2.2
 **/
@Component
@Mode("30")
public class VehLogHandler extends AbstractLogisticsHandler {

    @Autowired
    private LogisticsRegionMapper logisticsRegionMapper;

    /**
     * 关键属性值，避免使用时再查询数据库中的字段
     */
    //运输类型,1:物流运输,2:整车运输
//    private static final Integer CARRIER_TYPE = 2;
//    //快运方式名称
//    private static final String YFMODE_NAME = "物流整车运输";
//    //对应数据库的字段名
//    private static final String TABLE_FIELD_NAME = "transport_id";
    //对应常量的字段名
    private static final String CONSTANT_FIELD_NAME = "transportId";

    /**
     * 从具体实现类中获取字段，该字段的值等于该实现类在goodsShip中的一个字段
     *
     * @return
     */
    @Override
    protected String getShipFieldNameFromInstance() {
        return CONSTANT_FIELD_NAME;
    }

    /**
     * 关键属性值，避免使用时再查询数据库中的字段
     *
     * @param shipId       物流编号
     * @param modeId       运费模式
     * @param goodsId      商品ID
     * @param entId        仓库Id
     * @param quantity     采购数量
     * @param company      供应商Id
     * @param consignee    仓库省市区编号
     * @param boxVolume    整箱体积
     * @param singleVolume 单件体积
     * @param boxWeight    整箱重量
     * @param singleWeight 单件重量
     * @param QTYRate      箱规
     * @return
     * @throws Exception
     */
    @Override
    public Datas realHandle(GoodsShip goodsShip, Integer shipId, Integer modeId, Integer goodsId,
                            Integer entId, Integer quantity, Integer company, String consignee,
                            Double boxVolume, Double singleVolume, Double boxWeight, Double singleWeight,
                            Integer QTYRate) throws Exception {
        //1.获取物流对象
        //1.1 根据物流编号从数据库中获取对应的物流对象
        Logistics logistics = getLogistics(shipId);
        if (logistics == null) {
            throw new FreightCountFailureException("未查询到指定的物流承运商信息。");
        }
        Integer ifLevel = logistics.getIfLevel();
        //1.2调用父类方法获取可用的计价方式参数
        Map<String, Object> params = getAvailableParams(logistics, shipId, consignee);
        Double defaultPrice = (Double) params.get("defaultPrice");
        Double startingPrice = (Double) params.get("startingPrice");
        String levelRule = (String) params.get("levelRule");
        String levelPrice = (String) params.get("levelPrice");
        //1.3如果不存在级别设置,就返回默认值
        if (ifLevel == 0) {
            return packageDatas(modeId, goodsId, entId, quantity, defaultPrice);
        }
        /*
            2.开始计算
         */
        //2.1获取阶梯
        Integer countType = logistics.getCountType();
        Double freight = null;
        //获取级别字符串的长度
        int length = levelRule.split(",").length;
        String[] priceArr = levelPrice.split(",");
        if (length != priceArr.length) {
            throw new FreightCountFailureException("阶梯计价参数异常！");
        }

        switch (countType) {
            case 0:
                //计件数方式计算
                freight = countByNum(ifLevel, quantity, levelRule, defaultPrice, priceArr, length);
                break;
            case 1:
                //计重量方式计算
                freight = countByWeightOrVolume(ifLevel, quantity, defaultPrice, levelRule, priceArr, singleWeight, length);
                break;
            case 2:
                //计体积方式计算
                freight = countByWeightOrVolume(ifLevel, quantity, defaultPrice, levelRule, priceArr, singleVolume, length);
                break;
            default: //默认计件
                freight = countByNum(ifLevel, quantity, levelRule, defaultPrice, priceArr, length);
        }
        System.out.println("当前采购数量为：" + quantity + "，运费为：" + freight);

        if (freight == null) {
            throw new FreightCountFailureException("服务器开小差了，再试一次....");
        }
        if (freight.equals(Double.valueOf(0))) {
            throw new FreightToBeZeroExcption("运费计算结果为0！");
        }

        //调用直接父类方法封装返回结果
        return packageDatas(modeId, goodsId, entId, quantity, freight);
/*      由前端处理，后台不再判断
        //判断是否是送货上门
        switch (DELIVERY_TYPE) {
            case 2:
                datas.setIf_baoyou(1);
                break;
            default:
                datas.setIf_baoyou(0);
        }*/
    }

    /*
        整车运输模式的计算逻辑：
            判断是否超出最高档的限制：
            不超出：直接按照阶梯计算运价；
            超出：提示最大允许采购下单量为：XX件，超出部分提示请重新下单。
     */
    private Double countByNum(Integer ifLevel, Integer quantity, String levelRule, Double defaultPrice,
                              String[] priceArr, Integer length) throws OutOfLimitException, FreightCountFailureException {
        //1.没有级别设置则直接返回默认价格
        if (ifLevel == null || ifLevel == 0) {
            System.out.println("返回计重默认价格：" + defaultPrice);
            return defaultPrice;
        }
        //2.判断是否超出最高档的限制：
        Integer level = getLevelByComparand(Double.valueOf(quantity), levelRule);
        // 2.1如果当前采购数量所在的级别等于数组长度，则超出：
        if (level == length) {
            //todo 如何提示到php？没有地方封装允许最大采购数量。
            String[] levelArr = levelRule.split(",");
            int len = levelArr.length;
            Integer allowedMaxQuantity = Integer.parseInt(levelArr[len - 1]);
            throw new FreightCountFailureException("最大允许采购下单量为：" + allowedMaxQuantity + "件,超出部分提示请重新下单。");
        }
        // 2.2不超出：直接按照阶梯查询对应的阶梯运价；
        return Double.valueOf(priceArr[level]);
    }

    /*核心方法
         计重量方式计算:按照单件重量和数量计算总重量，按照阶梯计算总价格；
             判断总体积是否超出最高档的体积：
                 不超出：
                    给出计算结果；
                 超出：
                    最高档的体积值除以单件的体积为最大允许采购下单量。
                    提示最大允许采购下单量为：XX件，超出部分提示请重新下单。
    注：按体积计算和计重方式相同，只需要在singleWeightOrVolume入参时传入单件体积即可。
     */
    private Double countByWeightOrVolume(Integer ifLevel, Integer quantity, Double defaultPrice, String levelRule,
                                         String[] priceArr, Double singleWeightOrVolume, Integer length) throws FreightCountFailureException {
        //无阶梯设置--直接返回默认价格
        if (ifLevel == null || ifLevel == 0) {
            System.out.println("返回计重默认价格：" + defaultPrice);
            return defaultPrice;
        }
        //1.根据单件重量和数量计算获取总重量
        Double totalWeightOrVolume = singleWeightOrVolume * quantity;
        //2.判断是否超出最高档的限制：
        Integer level = getLevelByComparand(totalWeightOrVolume, levelRule);
        // 2.1如果当前采购数量所在的级别等于数组长度，则超出：
        if (level == length) {
            //todo 如何提示到php？没有地方封装允许最大采购数量。
            //计算最大允许下单量:最高档的重量值除以单件的重量,向下取整
            String[] levelArr = levelRule.split(",");
            int len = levelArr.length;
            BigDecimal maxLimitNum = new BigDecimal(levelArr[len - 1]);
            BigDecimal bSingleWeightOrVolume = new BigDecimal(singleWeightOrVolume);
            int allowedMaxQuantity = maxLimitNum.divideToIntegralValue(bSingleWeightOrVolume).setScale(0, BigDecimal.ROUND_DOWN).intValue();
            throw new FreightCountFailureException("最大允许采购下单量为：" + allowedMaxQuantity + "件,超出部分提示请重新下单。");
        }
        // 2.2不超出：直接按照阶梯查询对应的阶梯运价；
        return Double.valueOf(priceArr[level]);
    }
}
